/**

Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016.  All rights reserved.

Contact:
     SYSTAP, LLC DBA Blazegraph
     2501 Calvert ST NW #106
     Washington, DC 20008
     licenses@blazegraph.com

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/*
 * Created on Nov 15, 2006
 */
package com.bigdata.btree;

import java.util.NoSuchElementException;

/**
 * Visits the direct children of a {@link Node} in the external key ordering.
 * 
 * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
 * @version $Id$
 */
class ChildIterator implements INodeIterator {

    private final Node node;

    private int index = 0;

    private int lastVisited = -1;
    
//    private final byte[] fromKey;
//    
//    private final byte[] toKey;

    // first index to visit.
    private final int fromIndex;

    // first index to NOT visit.
    private final int toIndex;
    
    public ChildIterator(Node node) {

        this(node,null,null);
        
    }
    
    /**
     * 
     * @param node
     *            The node whose children will be traversed.
     * @param fromKey
     *            The first key whose child will be visited or <code>null</code>
     *            if the lower bound on the key traversal is not constrained.
     * @param toKey
     *            The first key whose child will NOT be visited or
     *            <code>null</code> if the upper bound on the key traversal is
     *            not constrained.
     * 
     * @exception IllegalArgumentException
     *                if fromKey is given and is greater than toKey.
     */
    public ChildIterator(final Node node, final byte[] fromKey, final byte[] toKey) {

        assert node != null;

        this.node = node;

//        this.fromKey = fromKey; // may be null (no lower bound).
//        
//        this.toKey = toKey; // may be null (no upper bound).

        { // figure out the first index to visit.

            int fromIndex;

            if (fromKey != null) {

                fromIndex = node.findChild(fromKey);

            } else {

                fromIndex = 0;

            }

            this.fromIndex = fromIndex;

        }

        {    /*
             * figure out the last index to visit.
             * 
             * Note: Unlike a leaf, we do visit the child in which the toKey
             * would be found.  This is necessary in order to ensure that we
             * visit any keys in leaves spanned by the child that are less
             * than the toKey.
             */

            int toIndex;

            if (toKey != null) {

                toIndex = node.findChild(toKey);

                if (fromIndex > toIndex) {
                    /*
                     * Note: we test for from/to key out of order _before_
                     * incrementing the toIndex.
                     */                    
                    throw new IllegalArgumentException("fromKey > toKey");
                    
                }
                
                // +1 so that we visit the child in which toKey would be found!
                toIndex++;
                
            } else {

                // Note: nchildren == nkeys+1 for a Node.
                toIndex = node.getKeyCount() + 1;

            }

            this.toIndex = toIndex;

        }

        // starting index is the lower bound.
        index = fromIndex;

    }

    public boolean hasNext() {

        return index >= fromIndex && index < toIndex;

    }

    public AbstractNode next() {

        if (!hasNext()) {

            throw new NoSuchElementException();

        }

        lastVisited = index++;
        
        return node.getChild(lastVisited);
        
    }

    public AbstractNode getNode() {
    
        if( lastVisited == -1 ) {
            
            throw new IllegalStateException();
            
        }
        
        return node.getChild(lastVisited);

    }

    public Object getKey() {

        if( lastVisited == -1 ) {
            
            throw new IllegalStateException();
            
        }
        
        return node.getKeys().get(lastVisited);
        
    }
    
    /**
     * @exception UnsupportedOperationException
     */
    public void remove() {

        throw new UnsupportedOperationException();

    }

}
